package net.kazed.nextaction.context.activity;

import java.util.Iterator;

import android.app.ListActivity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

import net.kazed.nextaction.NextActionApplication;
import net.kazed.nextaction.R;
import net.kazed.nextaction.database.ContextCache;
import net.kazed.nextaction.database.GtdContext;
import net.kazed.nextaction.database.Task;
import net.kazed.nextaction.database.TreeNode;

public class ContextView2Activity extends ListActivity {

   private static final String cTag = "ContextView2Activity";
	
   private static final int MENU_INSERT_CONTEXT = Menu.FIRST + 1;
   private static final int MENU_INSERT_TASK = Menu.FIRST + 2;
   private static final int MENU_DELETE_CONTEXT = Menu.FIRST + 3;
   
   private static final int NEW_TASK = 1;
   private static final int EDIT_TASK = 2; 
   private static final int VIEW_TASK = 3;
   private static final int VIEW_CONTEXT = 4;
   private static final int NEW_CONTEXT = 5;

	private TextView titleWidget;
   private TextView numberOfTasksText;
   private Button button;
	private long contextId;
	private Uri contextUri;
	private GtdContext context;
   private Cursor taskCursor;
   private ContextCache contextCache;
   private ContextTaskListAdapter listAdapter;
   private MotionEvent downStart;  

	@Override
    public void onCreate(Bundle icicle) {
		contextUri = getIntent().getData();
      setContentView(R.layout.context_task_list);
      setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
      
      titleWidget = (TextView) findViewById(R.id.context_name);
      numberOfTasksText = (TextView) findViewById(R.id.number_of_tasks);
      button = (Button) findViewById(R.id.edit_button);
      button.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            Intent intent = new Intent(ContextView2Activity.this, ContextEditorActivity.class);
            intent.setAction(Intent.ACTION_EDIT);
            intent.setData(contextUri);
            startActivity(intent);
         }
      });
      
      contextId = ContentUris.parseId(contextUri);
      
      taskCursor = managedQuery(Task.CONTENT_URI, Task.FULL_PROJECTION.getFieldNames(),
            Task.CONTEXT_ID + " = ?", new String[] {String.valueOf(contextId)}, 
            Task.CREATED_DATE + " ASC");
      
      NextActionApplication application = (NextActionApplication) getApplication();
      contextCache = application.getContextCache();
      listAdapter = new ContextTaskListAdapter(contextCache, (int) contextId, taskCursor);
      setListAdapter(listAdapter);
      
      getListView().setOnTouchListener(new ListOnTouchListener());
      
      super.onCreate(icicle);
	}
	
	@Override
	protected void onResume() {
	   context = contextCache.getContextTree((int) contextId).getData();
//      Cursor contextItemCursor = getContentResolver().query(contextUri, GtdContext.FULL_PROJECTION.getFieldNames(),
//            null, null, null);
//      if (contextItemCursor.moveToFirst()) {
//         context = new GtdContext(contextItemCursor);
//      }
//      contextItemCursor.close();

      titleWidget.setText(context.getAbsoluteContextPath(getContentResolver(), " > "));
      numberOfTasksText.setText(Integer.toString(context.getNumberOfTasks()));

		super.onResume();
	}
	
   @Override
   protected void onListItemClick(ListView l, View v, int position, long id) {
      Object item = listAdapter.getItem(position);
      if (item instanceof GtdContext) {
         GtdContext context = (GtdContext) item;
         Uri itemUri = ContentUris.withAppendedId(GtdContext.CONTENT_URI, context.getId());
         Intent intent = new Intent(Intent.ACTION_VIEW, itemUri);
         startActivityForResult(intent, VIEW_CONTEXT);
      } else if (item instanceof Task) {
         Task task = (Task) item;
         Uri itemUri = ContentUris.withAppendedId(Task.CONTENT_URI, task.getId());
         Intent intent = new Intent(Intent.ACTION_VIEW, itemUri);
         startActivityForResult(intent, VIEW_TASK);
      }
   }

   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
      taskCursor.requery();
      listAdapter.requery();
      if (requestCode == NEW_CONTEXT) {
         Uri newContextUri = data.getData();
         Log.d(cTag, "newContextUri: " + newContextUri);
         String idSegment = newContextUri.getLastPathSegment();
         if (idSegment != null) {
            int id = Integer.parseInt(idSegment);
            int position = listAdapter.getContextPosition(id);
            Log.d(cTag, "position: " + position);
            getListView().setSelection(position);
         }
      } else if (requestCode == NEW_TASK) {
         
      }
      onContentChanged();
   }

   /**
     * {@inheritDoc}
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       Resources resources = getResources();
       menu.add(0, MENU_INSERT_TASK, 0, resources.getString(R.string.menu_add_task))
          .setIcon(android.R.drawable.ic_menu_add).setAlphabeticShortcut('a');
       menu.add(0, MENU_INSERT_CONTEXT, 1, resources.getString(R.string.menu_add_context))
          .setIcon(android.R.drawable.ic_menu_add).setAlphabeticShortcut('c');
       menu.add(0, MENU_DELETE_CONTEXT, 2, resources.getString(R.string.menu_delete_context))
          .setIcon(android.R.drawable.ic_menu_delete).setAlphabeticShortcut('d');
       return super.onCreateOptionsMenu(menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       switch (item.getItemId()) {
       case MENU_INSERT_TASK:
          Uri itemUri = getContentResolver().insert(Task.CONTENT_URI, null);
          Intent intent = new Intent(Intent.ACTION_INSERT, itemUri);
          intent.putExtra(GtdContext.SELECTED_CONTEXT_ID, contextId);
          startActivityForResult(intent, NEW_TASK);
          break;
       case MENU_INSERT_CONTEXT:
          GtdContext newContext = new GtdContext("New context");
          newContext.setParentContextId(context.getId());
          ContentValues values = new ContentValues();
          newContext.toValues(values);
          Uri newContextUri = getContentResolver().insert(GtdContext.CONTENT_URI, values);

          Intent contextIntent = new Intent(Intent.ACTION_EDIT, newContextUri);
//          contextIntent.putExtra(GtdContext.SELECTED_CONTEXT_ID, contextId);
          startActivityForResult(contextIntent, NEW_CONTEXT);
          break;
       case MENU_DELETE_CONTEXT:
          // TODO update all tasks contained in this context, remove contextId
          getContentResolver().delete(contextUri, null, null);
          finish();
          break;
       }
       return super.onOptionsItemSelected(item);
    }

    private static class ContextTaskListAdapter implements ListAdapter {

      private ContextCache contextCache;
      private Integer contextId;
      private Cursor taskCursor;
      private int numberOfContexts;
      private int numberOfTasks;
      private int firstTaskPosition;
      private TreeNode<GtdContext> contextNode;

      /**
       * Constructor.
       * @param contextId Parent context ID.
       * @param taskCursor Cursor for retrieving tasks.
       */
      public ContextTaskListAdapter(ContextCache contextCache, Integer contextId, Cursor taskCursor) {
        this.contextCache = contextCache;
        this.contextId = contextId;
        this.taskCursor = taskCursor;
        requery();
      }
      
      public void requery() {
         Log.d(cTag, "requery");
         contextNode = contextCache.getContextTree(contextId);
         numberOfContexts = contextNode.getChildren().size();
//         taskCursor.requery();
         numberOfTasks = taskCursor.getCount(); 
         firstTaskPosition = numberOfContexts;
         Log.d(cTag, "requery: " + numberOfContexts + "-" + numberOfTasks);
      }
       
      /**
       * Get position of context with contextId.
       * @param contextId ID of context.
       * @return Position of context item, -1 if not found.
       */
      public int getContextPosition(int contextId) {
         int position = -1;
         int i = 0;
         for (Iterator<TreeNode<GtdContext>> nodeIterator = contextNode.getChildren().iterator();
               position == -1 && nodeIterator.hasNext();) {
            TreeNode<GtdContext> childNode = (TreeNode<GtdContext>) nodeIterator.next();
            if (contextId == childNode.getData().getId()) {
               position = i;
            }
            i++;
         }
         return position;
      }
       
      @Override
      public boolean areAllItemsEnabled() {
         return true;
      }

      @Override
      public boolean isEnabled(int position) {
         Log.d(cTag, "isEnabled: " + position);
         return isContextItem(position) || isTaskItem(position);
      }

      @Override
      public int getCount() {
         Log.d(cTag, "getCount: " + numberOfContexts + "-" + numberOfTasks);
         return numberOfContexts + numberOfTasks; // + 2;
      }

      @Override
      public Object getItem(int position) {
         // TODO Auto-generated method stub
         Log.d(cTag, "getItem: " + position);
         Object item = null;
         if (isContextItem(position)) {
            GtdContext context = contextNode.getChildren().get(position).getData();
            item = context;
         } else if (isTaskItem(position)) {
            taskCursor.moveToPosition(position - numberOfContexts);
            Task task = new Task(taskCursor);
            item = task;
         }
         return item;
      }

      @Override
      public long getItemId(int position) {
         // TODO Auto-generated method stub
         long itemId = 0;
         if (isContextItem(position)) {
            GtdContext context = contextNode.getChildren().get(position).getData();
            itemId = context.getId();
         } else if (isTaskItem(position)) {
            taskCursor.moveToPosition(position - numberOfContexts);
            Task task = new Task(taskCursor);
            itemId = 10000 + task.getId();
         } else {
            itemId = 1000000 + position;
         }

         Log.d(cTag, "getItemId: " + position + " - " + itemId);
         return itemId;
      }

      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
         View view = null;
         Log.d(cTag, "getView: " + position + "-" + convertView);
         
//         if (position == 0) {
//            TextView textView = null;
//            if (convertView instanceof TextView) {
//               textView = (TextView) convertView;
//            } else {
//               textView = new TextView(parent.getContext());
//            }
//            textView.setText("Contexts");
//            view = textView;
//            Log.d(cTag, "getView: textView " + view);
         if (isContextItem(position)) {
            ContextListItemView contextView = null;
            if (convertView instanceof ContextListItemView) {
               contextView = (ContextListItemView) convertView;
            } else {
               contextView = new ContextListItemView(parent.getContext(), R.layout.context_list_item_view);
            }
            GtdContext context = contextNode.getChildren().get(position).getData();
            contextView.updateView(context);
            view = contextView;
            Log.d(cTag, "getView: contextView " + view);
//         } else if (position == numberOfContexts + 1) {
//            TextView textView = null;
//            if (convertView instanceof TextView) {
//               textView = (TextView) convertView;
//            } else {
//               textView = new TextView(parent.getContext());
//            }
//            textView.setText("Tasks");
//            view = textView;
//            Log.d(cTag, "getView: textView " + view);
         } else if (isTaskItem(position)) {
            TaskListItemView taskView = null;
            if (convertView instanceof TaskListItemView) {
               taskView = (TaskListItemView) convertView;
            } else {
               taskView = new TaskListItemView(parent.getContext());
            }
            taskCursor.moveToPosition(position - numberOfContexts);
            Task task = new Task(taskCursor);
            taskView.updateView(task);
            view = taskView;
            Log.d(cTag, "getView: taskView " + view);
         } else {
            Log.d(cTag, "unknown view");
         }
         
         Log.d(cTag, "getView: return " + view);
         return view;
      }

      @Override
      public int getViewTypeCount() {
         int count = 0;
         if (numberOfContexts > 0) {
            count++;
         }
         if (numberOfTasks > 0) {
            count++;
         }
         Log.d(cTag, "getViewTypeCount: " + count);
         return 2;
      }

      @Override
      public int getItemViewType(int position) {
         int viewType = 0;
         if (isContextItem(position)) {
            viewType = 0;
         } else if (isTaskItem(position)) {
            viewType = 1;
         }
         Log.d(cTag, "getItemViewType: " + position + "-" + viewType);
         return viewType;
      }

      @Override
      public boolean hasStableIds() {
         Log.d(cTag, "hasStableIds");
         return false; 
      }

      @Override
      public boolean isEmpty() {
         Log.d(cTag, "isEmpty");
         return numberOfContexts == 0 && numberOfTasks == 0;
      }

      @Override
      public void registerDataSetObserver(DataSetObserver observer) {
         // TODO Auto-generated method stub
         Log.d(cTag, "registerDataSetObserver");
      }

      @Override
      public void unregisterDataSetObserver(DataSetObserver observer) {
         // TODO Auto-generated method stub
         Log.d(cTag, "unregisterDataSetObserver");
      }
      
      private boolean isContextItem(int position) {
         return (position >= 0 && position < numberOfContexts);
      }

      private boolean isTaskItem(int position) {
         return (position >= firstTaskPosition);
      }

    }

    private class ListOnTouchListener implements OnTouchListener {
       
       @Override
       public boolean onTouch(View view, MotionEvent event) {
          switch(event.getAction()) {
          case MotionEvent.ACTION_DOWN:
             // keep track of the starting down-event
             downStart = MotionEvent.obtain(event);
             Log.d(cTag, "ACTION_DOWN: " + event);
             break;
          case MotionEvent.ACTION_MOVE:
             Log.d(cTag, "ACTION_MOVE: " + event);
             if (isSwiped(view, event)) {
                Log.d(cTag, "ACTION_MOVE: swiped");
                // figure out which child view we crossed
                ListView list = (ListView) findViewById(android.R.id.list);
                int position = list.pointToPosition((int) downStart.getX(), (int) downStart.getY());
                Object item = listAdapter.getItem(position);
                Log.d(cTag, "crossed: " + item);
                if (item instanceof Task) {
                   Task task = (Task) item;
                   task.setComplete(!task.getComplete());
                   Log.d(cTag, "task: " + task.getDescription() + " - " + task.getComplete());
                   ContentValues values = new ContentValues();
                   task.toValues(values);
                   Uri taskUri = ContentUris.withAppendedId(Task.CONTENT_URI, task.getId());
                   getContentResolver().update(taskUri, values, null, null);
                   onContentChanged();
                }
                // and return true to consume this event
                return true;
             }
             break;
          case MotionEvent.ACTION_UP:
             Log.d(cTag, "ACTION_UP: " + event);
             if (isSwiped(view, event)) {
                Log.d(cTag, "ACTION_UP: swiped");
                return true;
             }
             break;
          }

          return false;
       }
       
       public boolean isSwiped(View view, MotionEvent event) {
          boolean swiped = false;
          float deltaX = event.getX() - downStart.getX();
          if(Math.abs(deltaX) > 10 * 2) {
             // check if we crossed an item
             float targetWidth = view.getWidth() / 4;
             float deltaY = event.getY() - downStart.getY();
             boolean movedAcross = (Math.abs(deltaX) > targetWidth);
             boolean steadyHand = (Math.abs(deltaX / deltaY) > 2);
             swiped = movedAcross && steadyHand;
          }
          return swiped;
       }

    }
    
}
